import {
  Controller,
  Get,
  Query,
  Post,
  Body,
  Put,
  Param,
  Delete,
  Req,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { Request } from 'express';
import { CreateUserDto as CreateDto } from './dtos/create.dto';
import { QueryUserDto as QueryDto } from './dtos/query.dto';
import { UpdateUserDto as UpdateDto } from './dtos/update.dto';
import { Permissions } from 'src/decorators/permissions.decorator';
import { UserService } from './user.service';
import { Op } from 'sequelize';
import type { Order } from 'sequelize';
import { Role } from 'src/role/role.model';
import { ApiBearerAuth, ApiTags, IntersectionType } from '@nestjs/swagger';
import { PaginatedDto } from 'src/dtos/paginated.dto';
import { ApiPaginatedResponse } from 'src/decorators/api-paginated-response.decorator';
import {
  ApiCommonDataBooleanResponse,
  ApiCommonDataResponse,
} from 'src/decorators/api-common-data-response.decorator';
import { ProfileDto } from './dtos/profile.dto';
import { ExtraModelDto } from 'src/dtos/extra-model.dto';

@ApiTags('user')
@ApiBearerAuth()
@Controller('user')
export class UserController {
  constructor(private userService: UserService) {}

  @Permissions('user.create')
  @HttpCode(HttpStatus.OK)
  @Post()
  @ApiCommonDataResponse(IntersectionType(CreateDto, ExtraModelDto))
  create(@Req() request: Request, @Body() createDto: CreateDto) {
    return this.userService.create(createDto);
  }

  @Permissions('user.findAll')
  @HttpCode(HttpStatus.OK)
  @Get()
  @ApiPaginatedResponse(CreateDto)
  findAll(
    @Req() request: Request,
    @Query() query: QueryDto,
  ): Promise<PaginatedDto<CreateDto>> {
    const search = [
      'search_username',
      'search_mobile',
      'search_email',
      'search_nickname',
      'search_real_name',
      'search_id_card',
      'search_description',
    ].filter((key) => query[key]);
    const where = {};
    if (search.length) {
      where[Op.or] = search.map((key) => ({
        [key.slice(7)]: {
          [Op.substring]: query[key],
        },
      }));
    }
    const sort = ['sort_created_at'];
    const order = sort.map((key) => [
      key.slice(5),
      query[key] === 'asc' ? 'asc' : 'desc',
    ]); // [["created_at", "desc"]]
    return this.userService.findAll(
      +query.limit,
      +query.page,
      where,
      order as Order,
    );
  }

  @Permissions('user.findOne')
  @HttpCode(HttpStatus.OK)
  @Get(':id')
  @ApiCommonDataResponse(IntersectionType(CreateDto, ExtraModelDto))
  findOne(@Req() request: Request, @Param('id') id: string) {
    // return this.userService.findByPk(id);
    return this.userService.findOneWith({ id }, Role);
  }

  @Permissions('user.update')
  @HttpCode(HttpStatus.OK)
  @Put(':id')
  @ApiCommonDataResponse(IntersectionType(UpdateDto, ExtraModelDto))
  update(
    @Req() request: Request,
    @Param('id') id: string,
    @Body() updateDto: UpdateDto,
  ) {
    return this.userService.update(id, updateDto);
  }

  @Permissions('user.remove')
  @HttpCode(HttpStatus.OK)
  @Delete(':id')
  @ApiCommonDataBooleanResponse()
  remove(@Req() request: Request, @Param('id') id: string) {
    return this.userService.remove(id);
  }

  @Permissions('user.removeBatch')
  @HttpCode(HttpStatus.OK)
  @Delete('batch/:ids')
  @ApiCommonDataBooleanResponse()
  removeBatch(@Req() request: Request, @Param('ids') ids: string) {
    return this.userService.removeBatch(ids.split(','));
  }

  @Permissions('user.getProfile')
  @HttpCode(HttpStatus.OK)
  @Get('profile/info')
  @ApiCommonDataResponse(ProfileDto)
  async getProfile(@Req() request: Request) {
    return this.userService.getProfile(request.user);
  }
}
